﻿using System;
using System.Diagnostics;
using System.IO;
using System.Net;
using System.Threading;
using System.Windows.Forms;
using Microsoft.Win32;

namespace Chromium_Updater
{
    public partial class MainForm : Form
    {
        string BaseUrl = "http://build.chromium.org/buildbot/snapshots/chromium-rel-xp/";
        bool DownloaderActive = false;
        //
        DownloadForm DownloadForm = null;
        //
        delegate void UpdateProcessor_Delegate(int RemoteVersion, bool Show);
        delegate void DownloadForm_Finished_Delegate(object sender, DownloadFinishedArgs myArgs);
        delegate void DownloadForm_ProgressChanged_Delegate(object sender, DownloadProgressArgs myArgs);
        delegate void ShowBalloonMsg_Delegate(string txt);
        delegate void LocalVersion_Delegate(string ver);

        public MainForm()
        {
            InitializeComponent();
        }

        #region Form Events

        private void Main_Load(object sender, EventArgs e)
        {
            if (Settings.MinimizeOnStart) { this.WindowState = FormWindowState.Minimized; }
            //
            timer1.Interval = Settings.CheckInterval;
            label3.Text = Settings.LocalVersion.ToString();
            //
            CheckForUpdate(false);
        }

        private void MainForm_FormClosing(object sender, FormClosingEventArgs e)
        {
            if (DownloaderActive)
                if (MessageBox.Show("Chromium Updater is currently downloading the newest revision. Are you sure you want to exit?", "Chromium Updater", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    e.Cancel = true;
            //
            notifyIcon1.Dispose();
            //
            Environment.Exit(0);
        }

        private void timer1_Tick(object sender, EventArgs e)
        {
            CheckForUpdate(false);
        }

        private void button1_Click(object sender, EventArgs e)
        {
            CheckForUpdate(true);
            //
            timer1.Interval = Settings.CheckInterval;
        }

        private void button3_Click(object sender, EventArgs e)
        {
            new SettingsForm()._Show();
        }

        private void pictureBox1_Click(object sender, EventArgs e)
        {
            new AboutForm()._Show();
        }

        private void button2_Click(object sender, EventArgs e)
        {
            if (button2.Text == "Cancel" && DownloadForm != null)
                DownloadForm.button1_Click(this, null);
            else
                Downloader();
        }

        private void label3_Click(object sender, EventArgs e)
        {
            Process.Start(BaseUrl + label3.Text + "/changelog.xml");
        }

        private void label4_Click(object sender, EventArgs e)
        {
            Process.Start(BaseUrl + label4.Text + "/changelog.xml");
        }

        #endregion

        #region Tray Events

        private void exitToolStripMenuItem_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void MainForm_Resize(object sender, EventArgs e)
        {
            if (this.WindowState == FormWindowState.Minimized)
            {
                this.ShowIcon = false;
                this.ShowInTaskbar = false;
            }
        }

        private void notifyIcon1_MouseDoubleClick(object sender, MouseEventArgs e)
        {
            this.WindowState = FormWindowState.Normal;
            this.ShowIcon = true;
            this.ShowInTaskbar = true;
        }

        private void checkToolStripMenuItem_Click(object sender, EventArgs e)
        {
            CheckForUpdate(true);
            //
            timer1.Interval = Settings.CheckInterval;
        }

        private void downloadToolStripMenuItem_Click(object sender, EventArgs e)
        {
            Downloader();
        }

        private void settingsToolStripMenuItem_Click(object sender, EventArgs e)
        {
            new SettingsForm()._Show();
        }

        #endregion

        #region UpdateChecker

        private void CheckForUpdate(bool show)
        {
            new Thread(new ParameterizedThreadStart(CheckForUpdateWorker)).Start(Convert.ToInt32(show));
        }

        private void CheckForUpdateWorker(object show)
        {
            HttpWebRequest myRequest = (HttpWebRequest)WebRequest.Create(BaseUrl + "LATEST");
            myRequest.Method = "GET";
            WebResponse myResponse;
            try
            {
                myResponse = myRequest.GetResponse();
            }
            catch (WebException)
            {
                return;
            }
            StreamReader sr = new StreamReader(myResponse.GetResponseStream(), System.Text.Encoding.UTF8);
            string result = sr.ReadToEnd();
            sr.Close();
            myResponse.Close();
            //
            UpdateProcessor(Convert.ToInt32(result), Convert.ToBoolean(Convert.ToInt32(show)));
        }

        private void UpdateProcessor(int RemoteVersion, bool Show)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new UpdateProcessor_Delegate(UpdateProcessor), new object[] { RemoteVersion, Show });
                return;
            }
            //
            label4.Text = RemoteVersion.ToString();
            //
            if (!DownloaderActive)
            {
                button2.Enabled = true;
                downloadToolStripMenuItem.Enabled = true;
            }
            //
            if (RemoteVersion > Settings.LocalVersion)
            {
                notifyIcon1.Text = "Chromium Updater - r" + RemoteVersion.ToString() + " available";
                notifyIcon1.ShowBalloonTip(5000, "Chromium Updater", "Chromium r" + RemoteVersion.ToString() + " is available.", ToolTipIcon.Info);
            }
            else if (Show)
                notifyIcon1.ShowBalloonTip(5000, "Chromium Updater", "You are using the latest Chromium revision.", ToolTipIcon.Info);
        }

        #endregion

        #region Downloader

        private void Downloader()
        {
            DownloaderActive = true;
            //
            button2.Text = "Cancel";
            button3.Enabled = false;
            downloadToolStripMenuItem.Enabled = false;
            settingsToolStripMenuItem.Enabled = false;
            //
            string DownFrom = BaseUrl + "//" + label4.Text + "//";
            string DownTo = Settings.DownloadTo;
            //make sure backslash at end
            if (DownTo[DownTo.Length - 1] != '/') { DownTo += "//"; }
            //make sure folder exists
            if (!Directory.Exists(DownTo.Substring(0, DownTo.Length - 1))) { Directory.CreateDirectory(DownTo.Substring(0, DownTo.Length - 1)); }
            //
            if (Settings.DownloadAs == 0)
            {
                DownFrom += "mini_installer.exe";
                if (Settings.AppendFileName)
                    DownTo += "mini_installer_r" + label4.Text + ".exe";
                else
                    DownTo += "mini_installer.exe";
            }
            else
            {
                DownFrom += "chrome-win32.zip";
                if (Settings.AppendFileName)
                    DownTo += "chrome-win32_r" + label4.Text + ".zip";
                else
                    DownTo += "chrome-win32.zip";
            }
            //
            DownloadForm = new DownloadForm();
            DownloadForm.Finished += new Finished_Handler(DownloadForm_Finished);
            DownloadForm.ProgressChanged += new Progress_Handler(DownloadForm_ProgressChanged);
            DownloadForm.Start(DownFrom, DownTo);
        }

        private void DownloadForm_Finished(object sender, DownloadFinishedArgs myArgs)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new DownloadForm_Finished_Delegate(DownloadForm_Finished), new object[] { sender, myArgs });
                return;
            }
            //
            button2.Text = "Download";
            downloadToolStripMenuItem.Text = "Download";
            notifyIcon1.Text = "Chromium Updater";
            //
            if (myArgs.Error == DownloadFinishedArgs.ErrorCode.None)
            {
                if (Settings.DownloadAs == 0)
                {
                    if (CloseChromium())
                    {
                        ChromiumRegistryWatcher();
                        try
                        {
                            Process.Start(myArgs.FullFilePath);
                        }
                        catch (System.ComponentModel.Win32Exception)
                        {
                            ShowBalloonMsg("Chromium r" + label4.Text + " failed to run. Please try again later.");
                        }
                    }
                    else
                        ShowBalloonMsg("Chromium r" + label4.Text + " installer was not ran because Chromium is still running.");
                }
                else
                {
                    label3.Text = label4.Text;
                    Settings.LocalVersion = Convert.ToInt32(label4.Text);
                    //
                    ShowBalloonMsg("Chromium r" + label3.Text + " archive downloaded.");
                }
            }
            else if (myArgs.Error == DownloadFinishedArgs.ErrorCode.RemoteFileNotFound)
                ShowBalloonMsg("Chromium Updater could not find the remote file. Please try again later.");
            //
            button2.Enabled = true;
            button3.Enabled = true;
            downloadToolStripMenuItem.Enabled = true;
            settingsToolStripMenuItem.Enabled = true;
            //
            DownloadForm = null;
            DownloaderActive = false;
        }

        private void DownloadForm_ProgressChanged(object sender, DownloadProgressArgs myArgs)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new DownloadForm_ProgressChanged_Delegate(DownloadForm_ProgressChanged), new object[] { sender, myArgs });
                return;
            }
            //
            if (Settings.HideDownloader)
            {
                downloadToolStripMenuItem.Text = "Downloading (" + myArgs.PercentDone.ToString() + "%)";
                notifyIcon1.Text = "Chromium Updater - Downloading (" + myArgs.PercentDone.ToString() + "%)";
            }
        }

        #endregion

        #region Chromium

        private bool CloseChromium()
        {
            Process[] Procs = Process.GetProcessesByName("chrome");
            if (Procs.Length > 0)
            {
                if (MessageBox.Show("Chromium needs to be closed before it can be updated. Would you like Chormium Updater to go ahead and close it for you?", "Chromium Updater", MessageBoxButtons.YesNo, MessageBoxIcon.Question) == DialogResult.No)
                    return false;
                foreach (Process Proc in Procs)
                {
                    if (!Proc.HasExited) { Proc.Kill(); }
                }
                return true;
            }
            else { return true; }
        }

        private void ChromiumRegistryWatcher()
        {
            new Thread(new ParameterizedThreadStart(this.ChromiumRegistryWatcherWorker)).Start();
        }

        private void ChromiumRegistryWatcherWorker(object obj)
        {
            clsRegistry reg = new clsRegistry();
            reg.DeleteValue(Registry.CurrentUser, "Software\\Chromium", "InstallerResult");
            reg.DeleteValue(Registry.CurrentUser, "Software\\Chromium", "InstallerResultUIString");
            Stopwatch StopWatch = new Stopwatch();
            StopWatch.Start();
            while (true)
            {
                uint result = reg.GetDWORDValue(Registry.CurrentUser, "Software\\Chromium", "InstallerResult");
                if (reg.strRegError == null)
                {
                    if (result == 0)
                    {
                        ShowBalloonMsg("Chromium r" + label4.Text + " installer ran and was succesfully installed.");
                        //
                        LocalVersion(label4.Text);
                        Settings.LocalVersion = Convert.ToInt32(label4.Text);
                        //
                        if (Settings.OpenChromiumAfter)
                        {
                            string ChromiumPath = reg.GetStringValue(Registry.CurrentUser, "Software\\Chromium", "InstallerSuccessLaunchCmdLine");
                            if (reg.strRegError == null)
                                Process.Start(ChromiumPath);
                            else
                                ShowBalloonMsg("Chromium r" + label3.Text + " couldn't be started by Chromium Updater.");
                        }
                        break;
                    }
                }
                //
                string error = reg.GetStringValue(Registry.CurrentUser, "Software\\Chromium", "InstallerResultUIString");
                if (reg.strRegError == null)
                {
                    ShowBalloonMsg("Chromium r" + label4.Text + " installer ran and was unsuccesfully installed. Error: " + error);
                    break;
                }
                //
                if (StopWatch.ElapsedMilliseconds > 60000)
                {
                    ShowBalloonMsg("Chromium r" + label4.Text + " installer ran and was unsuccesfully installed. Error: Registry watch timeout");
                    break;
                }
                Thread.Sleep(100);
            }
        }

        #endregion

        #region Functions

        private void LocalVersion(string ver)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new LocalVersion_Delegate(LocalVersion), new object[] { ver });
                return;
            }
            //
            label3.Text = ver;

        }

        private void ShowBalloonMsg(string txt)
        {
            if (InvokeRequired)
            {
                BeginInvoke(new ShowBalloonMsg_Delegate(ShowBalloonMsg), new object[] { txt });
                return;
            }
            //
            notifyIcon1.ShowBalloonTip(5000, "Chromium Updater", txt, ToolTipIcon.Info);
        }

        #endregion
    }
}
